<?php

	/**
	 * @see Bike_Initial
	 */
	require_once 'Bike/Initial.php';
	
	/**
	 * @see Bike_Cli_Interface
	 */
	require_once 'Bike/Cli/Interface.php';

	
	abstract class Bike_Cli_Abstract extends Bike_Initial implements Bike_Cli_Interface
	{
		static public $_application;

		protected $_settings;

		static public function getFrontController()
		{
			return Zend_Controller_Front::getInstance();
		}

		static public function getApplication()
		{
			return self::$_application;
		}

		static public function setApplication(Zend_Application $Application)
		{
			self::$_application = $Application;
		}

		static public function getBootstrap()
		{			return self::getApplication()->getBootstrap();
		}

		public function __construct()
		{
			$args = func_get_args();
			$this->beforeInit();
			$options = $this->makeOptions($args);
			parent::__construct($options);
		}

		public function beforeInit()
		{

		}

		public function run()
		{			Throw new Bike_Cli_Exception('Undefined method '.get_class($this).'::run()');
		}

		public function getAliases()
		{			return array();
		}

		public function getAlias($Position)
		{
			$aliases = $this->getAliases();
			if(!isset($aliases[$Position]))
			{				Throw new Bike_Cli_Exception('Undefined alias for position '.$Position);
			}
			return $aliases[$Position];
		}

		public function makeOptions(array $Args=null)
		{			$options = array();
			foreach($Args as $n => $value)
			{				try
				{					$key = $this->getAlias($n);
				}
				catch(Bike_Cli_Exception $e)
				{					$key = $n;
				}
				$options[$key] = unserialize($value);
			}
			return $options;
		}

        public function __set($Name, $Value)
	    {
	        $methodName = 'set'.ucfirst($Name);
	        $this->$methodName($Value);
	    }

	    public function __get($Name)
	    {
	        $methodName = 'get'.ucfirst($Name);
		    return $this->$methodName();
	    }

		public function __call($MethodName, array $Args=null)
		{
			try
			{
				return parent::__call($MethodName, $Args);
			}
			catch(Bike_Exception $e)
			{
				if(substr($MethodName, 0, 3) == 'get')
	    		{
	    			$Name = substr($MethodName, 3);
	    			$name = $this->lowerCaseFirst($Name);
	    			$Value = $this->__getSetting($Name);
	    			if(method_exists($this, 'processGet'.$Name))
			        {
			        	$Value = call_user_func(array($this, 'processGet'.$Name), $Value);
			        }
	    			return $Value;
	    		}
	    		elseif(substr($MethodName, 0, 5) == 'unset')
	    		{
	    			$name = substr($MethodName, 5);
	    			return $this->__unsetSetting($name);
	    		}
	    		elseif(substr($MethodName, 0, 5) == 'isset')
	    		{
	    			$name = substr($MethodName, 5);
	    			return $this->__issetSetting($name);
	    		}
	    		elseif(substr($MethodName, 0, 3) == 'set')
	    		{
	    			$Name = substr($MethodName, 3);
	    			$name = $this->lowerCaseFirst($Name);
	    			if(sizeof($Args) <= 1)
	    			{
	    				$Value = reset($Args);
	    			}
	    			else
	    			{
	    				$Value = $Args;
	    			}
	    			if(method_exists($this, 'processSet'.$Name))
			        {
			        	$value = call_user_func(array($this, 'processSet'.$Name), $Value);
			        }
			        else
			        {
			        	$value = $Value;
			        }
	    			$this->__setSetting($Name, $value);
	    			return $this;
	    		}
    		}
    		Throw new Bike_Js_Exception('Undefined method: '.$MethodName);
		}

		protected function lowerCaseFirst($Name)
		{
			return Bike_String::factory($Name)->lowerCaseFirst();
		}

		private function __setSetting($Name, $Value)
		{
			$name = $this->lowerCaseFirst($Name);
			if(!is_array($this->_settings))
			{
				$this->_settings = array();
			}
			$this->_settings[$name]	= $Value;
			return $this;
		}

		private function __getSetting($Name)
		{
			return @$this->_settings[$this->lowerCaseFirst($Name)];
		}

		private function __unsetSetting($Name)
		{
			unset($this->_settings[$this->lowerCaseFirst($Name)]);
			return $this;
		}

		private function __issetSetting($Name)
		{
			return isset($this->_settings[$this->lowerCaseFirst($Name)]);
		}

		public function setSettings(array $Values)
		{
			foreach($Values as $name => $value)
			{
				$this->$name = $value;
			}
			return $this;
		}

		public function unsetSettings()
		{
			$this->_settings = array();
			return $this;
		}
	}
